package com.zhexiao.convert.utils;


import com.zhexiao.convert.entity.model.CellContent;
import com.zhexiao.convert.entity.model.ColumnContent;
import com.zhexiao.convert.entity.model.ParagraphStyle;
import com.zhexiao.convert.entity.model.RunStyle;
import com.zhexiao.convert.exceptions.WordException;
import lombok.Getter;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.FileOutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;

/**
 * @author zhe.xiao
 * @date 2021-01-20 15:46
 */
public class Word {
    private static Logger log = LoggerFactory.getLogger(Word.class);

    private XWPFDocument doc = null;

    public Word() {
        this.doc = new XWPFDocument();
    }

    /**
     * 段落生成器
     */
    public static class ParagraphBuilder {
        private Word word;

        private String text;
        private ParagraphStyle paragraphStyle;
        private RunStyle runStyle;

        public static ParagraphBuilder builder(Word word) {
            ParagraphBuilder builder = new ParagraphBuilder();
            builder.word = word;

            ParagraphStyle defaultParagraphStyle = new ParagraphStyle();
            defaultParagraphStyle.setAlignment(ParagraphAlignment.LEFT);
            builder.paragraphStyle = defaultParagraphStyle;

            RunStyle defaultRunStyle = new RunStyle();
            defaultRunStyle.setBold(false).setColor("000000").setFontSize(14).setFontFamily("微软雅黑");
            builder.runStyle = defaultRunStyle;

            return builder;
        }

        public ParagraphBuilder setText(String text) {
            this.text = text;
            return this;
        }

        public ParagraphBuilder setParagraphStyle(ParagraphStyle paragraphStyle) {
            this.paragraphStyle = paragraphStyle;

            return this;
        }

        public ParagraphBuilder setRunStyle(RunStyle runStyle) {
            this.runStyle = runStyle;
            return this;
        }

        public void build() {
            word.createParagraph(this);
        }
    }

    /**
     * 表格生成器
     */
    @Getter
    public static class TableBuilder {
        private Word word;

        //表格宽度
        private Integer tableWidth = 9072;

        //默认的表格是2列11行
        private Integer columnNum = 2;
        private Integer rowNum = 11;

        //列宽度
        private int[] columnWidth = new int[]{800, 5000};

        //行高度
        private Integer rowHeight = null;

        //边框样式
        private STBorder.Enum borderStyle = null;

        //设置列内容
        private List<ColumnContent> columnContents = new ArrayList<>();

        public static TableBuilder builder(Word word) {
            TableBuilder tableBuilder = new TableBuilder();
            tableBuilder.word = word;

            return tableBuilder;
        }

        public TableBuilder setTableWidth(Integer tableWidth) {
            this.tableWidth = tableWidth;
            return this;
        }

        public TableBuilder setColumnNum(Integer columnNum) {
            this.columnNum = columnNum;
            return this;
        }

        public TableBuilder setRowNum(Integer rowNum) {
            this.rowNum = rowNum;
            return this;
        }

        public TableBuilder setColumnWidth(int[] columnWidth) {
            this.columnWidth = columnWidth;
            return this;
        }

        public TableBuilder setRowHeight(Integer rowHeight) {
            this.rowHeight = rowHeight;
            return this;
        }

        public TableBuilder setBorderStyle(STBorder.Enum borderStyle) {
            this.borderStyle = borderStyle;
            return this;
        }

        public TableBuilder setColumnContent(ColumnContent columnContent) {
            if (columnContent.getColumnData().length != this.rowNum) {
                throw new WordException("列的内容数不匹配");
            }

            if (columnContent.getColumnNum() > (this.columnNum - 1)) {
                throw new WordException("列数不匹配");
            }

            this.columnContents.add(columnContent);
            return this;
        }

        public void build() {
            word.createTable(this);
        }

        /**
         * 配置表格基础配置
         *
         * @param table
         */
        private void configureBasicStyle(XWPFTable table) {
            CTTbl ctTbl = table.getCTTbl();

            //table属性
            CTTblPr tblPr = ctTbl.getTblPr();

            //设置表格边框样式
            if (null != this.borderStyle) {
                CTTblBorders ctTblBorders = tblPr.addNewTblBorders();
                ctTblBorders.addNewLeft().setVal(this.borderStyle);
                tblPr.setTblBorders(ctTblBorders);
            }

            //设置表格中cell的长度不随着文字变化而变化
            CTTblLayoutType layoutType = tblPr.addNewTblLayout();
            layoutType.setType(STTblLayoutType.FIXED);

            //设置宽度
            CTTblWidth tblW = tblPr.getTblW();
            tblW.setW(new BigInteger(String.valueOf(this.tableWidth)));
            tblW.setType(STTblWidth.DXA);
        }

        /**
         * 为每个cell创建样式
         *
         * @param table
         */
        private void configureCellStyle(XWPFTable table) {
            List<XWPFTableRow> rowList = table.getRows();
            rowList.forEach(row -> {
                //设置行高
                if (null != this.rowHeight) {
                    CTTrPr trPr = row.getCtRow().addNewTrPr();
                    CTHeight ht = trPr.addNewTrHeight();
                    ht.setVal(BigInteger.valueOf(this.rowHeight));
                }

                //单位元设置
                List<XWPFTableCell> cells = row.getTableCells();
                cells.forEach(cell -> {
                    //cell段落内容
                    XWPFParagraph cellParagraph;
                    if (CollectionUtils.isEmpty(cell.getParagraphs())) {
                        cellParagraph = cell.addParagraph();
                    } else {
                        cellParagraph = cell.getParagraphs().get(0);
                    }
                    cellParagraph.setAlignment(ParagraphAlignment.LEFT);

                    //cell居中样式
                    CTTcPr cttcpr = cell.getCTTc().addNewTcPr();
                    cttcpr.addNewVAlign().setVal(STVerticalJc.CENTER);
                });
            });
        }


        /**
         * 设置列宽度
         *
         * @param table
         */
        private void configureColumnWidth(XWPFTable table) {
            List<XWPFTableRow> rows = table.getRows();
            rows.forEach(row -> {
                List<XWPFTableCell> cells = row.getTableCells();

                //验证列数是否与列的宽度值数量一致
                if (this.columnWidth.length != cells.size()) {
                    log.info("cell的宽度数组与cell数量不匹配:{}, {}", this.columnWidth.length, cells.size());
                    throw new WordException("cell的宽度数组与cell数量不匹配");
                }

                //设置宽度
                for (int i = 0; i < cells.size(); i++) {
                    XWPFTableCell cell = cells.get(i);
                    cell.getCTTc().addNewTcPr().addNewTcW().setW(new BigInteger(String.valueOf(this.columnWidth[i])));
                }
            });
        }

        /**
         * 设置某一个列的内容
         */
        private void configureColumnContent(XWPFTable table) {
            if (!this.columnContents.isEmpty()) {
                columnContents.forEach(columnContent -> {
                    List<XWPFTableRow> rows = table.getRows();
                    for (int i = 0; i < rows.size(); i++) {
                        //获取列cell
                        XWPFTableRow row = rows.get(i);
                        XWPFTableCell cell = row.getCell(columnContent.getColumnNum());

                        //设置值和属性
                        XWPFParagraph paragraph = cell.getParagraphs().get(0);
                        XWPFRun run = paragraph.createRun();

                        //填充数据和样式
                        CellContent cellContent = columnContent.getColumnData()[i];
                        String content = cellContent.getContent();

                        //找到存在换行的数据换行
                        String[] strings = content.split("<br>");
                        for (String string : strings) {
                            run.setText(string);
                            if (strings.length > 1) {
                                run.addBreak(BreakType.TEXT_WRAPPING);
                            }
                        }

                        word.configureRunStyle(run, cellContent.getRunStyle());
                    }
                });
            }
        }
    }

    /**
     * 创建一个空白行
     */
    public void addBreak() {
        this.doc.createParagraph();
    }

    /**
     * 保存文件
     *
     * @param file
     */
    public void save(String file) {
        try (FileOutputStream out = new FileOutputStream(file)) {
            doc.write(out);
        } catch (Exception e) {
            log.error("文件保存失败, e={}", e.getMessage());
        }
    }

    /**
     * 创建段落
     *
     * @param paragraphBuilder
     */
    protected void createParagraph(ParagraphBuilder paragraphBuilder) {
        XWPFParagraph paragraph = this.doc.createParagraph();
        this.configureParagraphStyle(paragraph, paragraphBuilder.paragraphStyle);

        XWPFRun run = paragraph.createRun();
        run.setText(paragraphBuilder.text);
        this.configureRunStyle(run, paragraphBuilder.runStyle);
    }

    /**
     * 创建表格
     *
     * @param tableBuilder
     */
    public void createTable(TableBuilder tableBuilder) {
        XWPFTable table = this.doc.createTable(tableBuilder.rowNum, tableBuilder.columnNum);
        tableBuilder.configureBasicStyle(table);
        tableBuilder.configureCellStyle(table);
        tableBuilder.configureColumnWidth(table);
        tableBuilder.configureColumnContent(table);
    }

    /**
     * 配置段落的样式
     *
     * @param paragraph
     * @param paragraphStyle
     */
    private void configureParagraphStyle(XWPFParagraph paragraph, ParagraphStyle paragraphStyle) {
        if (!StringUtils.isEmpty(paragraphStyle.getAlignment())) {
            paragraph.setAlignment(paragraphStyle.getAlignment());
        }
    }

    /**
     * 配置文本的样式
     *
     * @param run
     * @param runStyle
     */
    private void configureRunStyle(XWPFRun run, RunStyle runStyle) {
        if (!StringUtils.isEmpty(runStyle.getFontSize())) {
            run.setFontSize(runStyle.getFontSize());
        }

        if (!StringUtils.isEmpty(runStyle.getBold())) {
            run.setBold(runStyle.getBold());
        }

        if (!StringUtils.isEmpty(runStyle.getFontFamily())) {
            run.setFontFamily(runStyle.getFontFamily());
        }

        if (!StringUtils.isEmpty(runStyle.getColor())) {
            run.setColor(runStyle.getColor());
        }
    }
}
